﻿package com.thorqq.magictimer;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;

import com.thorqq.magictimer.util.Util;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.widget.Toast;

/**
 * 自定义的 异常处理类 , 实现了 UncaughtExceptionHandler接口
 * 
 * @author Administrator
 * 
 */
public class MyCrashHandler implements UncaughtExceptionHandler
{
    // 需求是 整个应用程序 只有一个 MyCrash-Handler
    private static MyCrashHandler myCrashHandler;
    private Context context;
    //系统默认的UncaughtException处理类   
    private Thread.UncaughtExceptionHandler mDefaultHandler;  
    // private DoubanService service;
    //private SimpleDateFormat dataFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");

    // 1.私有化构造方法
    private MyCrashHandler()
    {

    }

    public static synchronized MyCrashHandler getInstance()
    {
        if (myCrashHandler != null)
        {
            return myCrashHandler;
        } else
        {
            myCrashHandler = new MyCrashHandler();
            return myCrashHandler;
        }
    }

    public void init(Context context)
    {
        this.context = context;
        // this.service = service;
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();  
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    public void uncaughtException(Thread thread, Throwable ex)
    {
        System.out.println("程序发生异常");
        Toast.makeText(this.context, "程序发生异常", Toast.LENGTH_SHORT).show();
        Util.logByForce("程序发生异常");
        
        // 1.获取当前程序的版本号. 版本的id
        String versioninfo = getVersionInfo();

        // 2.获取手机的硬件信息.
        String mobileInfo = getMobileInfo();

        // 3.把错误的堆栈信息 获取出来
        String errorinfo = getErrorInfo(ex);

        // 4.把所有的信息 还有信息对应的时间 提交到服务器
        try
        {
            // service.createNote(new PlainTextConstruct(dataFormat.format(new
            // Date())),
            // new PlainTextConstruct(versioninfo+mobileInfo+errorinfo),
            // "public", "yes");
            Util.logByForce("VersionInfo: \n" + versioninfo);
            Util.logByForce("MobileInfo: \n" + mobileInfo);
            Util.logByForce("ErrorInfo: \n" + errorinfo);     

        } catch (Exception e)
        {
            Util.log_ex(e);
        }

        // 干掉当前的程序
        //android.os.Process.killProcess(android.os.Process.myPid());
        
        //debug模式下不捕捉异常
        if(Util.is_debug())
        {
            mDefaultHandler.uncaughtException(thread, ex); 
        }
    }

    /**
     * 获取错误的信息
     * 
     * @param arg1
     * @return
     */
    private String getErrorInfo(Throwable ex)
    {
        Writer writer = new StringWriter();
        PrintWriter pw = new PrintWriter(writer);
        ex.printStackTrace(pw);
        pw.close();
        String error = writer.toString();
        return error;
    }

    /**
     * 获取手机的硬件信息
     * 
     * @return
     */
    private String getMobileInfo()
    {
        StringBuffer sb = new StringBuffer();
        // 通过反射获取系统的硬件信息
        try
        {

            Field[] fields = Build.class.getDeclaredFields();
            for (Field field : fields)
            {
                // 暴力反射 ,获取私有的信息
                field.setAccessible(true);
                String name = field.getName();
                String value = field.get(null).toString();
                sb.append(name + "=" + value);
                sb.append("\n");
            }
        } catch (Exception e)
        {
            Util.log_ex(e);
        }
        return sb.toString();
    }

    /**
     * 获取手机的版本信息
     * 
     * @return
     */
    private String getVersionInfo()
    {
        try
        {
            PackageManager pm = context.getPackageManager();
            PackageInfo info = pm.getPackageInfo(context.getPackageName(), 0);
            return info.versionName + "(" + info.versionCode + ")";
        } catch (Exception e)
        {
            Util.log_ex(e);
            return "版本号未知";
        }
    }
}
